/**
 * 
 */
package idv.takeshi.software.productline.bookstore.presentation.web.function;

import java.util.Collection;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;

import idv.takeshi.software.productline.bookstore.domain.model.book.InventoryStatus;
import idv.takeshi.software.productline.bookstore.domain.model.category.Category;
import idv.takeshi.software.productline.bookstore.domain.model.order.Atm;
import idv.takeshi.software.productline.bookstore.domain.model.order.CashInConvenientStore;
import idv.takeshi.software.productline.bookstore.domain.model.order.CreditCard;
import idv.takeshi.software.productline.bookstore.domain.model.order.DuplicateInvoice;
import idv.takeshi.software.productline.bookstore.domain.model.order.DuplicateInvoiceWithCashier;
import idv.takeshi.software.productline.bookstore.domain.model.order.Invoice;
import idv.takeshi.software.productline.bookstore.domain.model.order.OrderItemStatus;
import idv.takeshi.software.productline.bookstore.domain.model.order.OrderStatus;
import idv.takeshi.software.productline.bookstore.domain.model.order.Payment;
import idv.takeshi.software.productline.bookstore.domain.model.order.PickingListStatus;
import idv.takeshi.software.productline.bookstore.domain.model.order.PostalOrder;
import idv.takeshi.software.productline.bookstore.domain.model.useraccount.IndividualAccount;
import idv.takeshi.software.productline.bookstore.domain.model.useraccount.OrganizationAccount;
import idv.takeshi.software.productline.bookstore.domain.model.useraccount.UserAccount;

/**
 * A class to rpovide EL-based convenient functions.
 * @author takeshi
 *
 */
public class Functions {
	
	private Functions(){}
	
	/**
	 * Get message code by given inventory status enum.
	 * @param status
	 * @return
	 */
	public static final String getInventoryStatusMessageCode(InventoryStatus status){
		Validate.notNull(status, "inventory status shall always not be null/empty");
		
		String code = null;
		
		switch(status){
		
		case ACTIVE:
			code = "inventory.status.active";
			break;
		case INACTIVE:
			code = "inventory.status.inactive";
			break;
		case OUT_OF_PRINT:
			code = "inventory.status.outOfPrint";
			break;
		case REPLENISH_AFTER_ORDERED:
			code = "inventory.status.replenishAfterOrdered";
			break;
		default:	
			throw new RuntimeException("undefined inventory status:" + status);
		}
		
		return code;
	}
	
	/**
	 * Get message code by given payment.
	 * @param payment
	 * @return
	 */
	public static final String getPaymentMessageCode(Payment payment){
		Validate.notNull(payment, "payment shall always not be null");
		String code = null;
		
		if(payment instanceof CashInConvenientStore){
			code = "payment.cashInConvenientStore";
		} else if(payment instanceof CreditCard){
			code = "payment.creditCard";
		} else if(payment instanceof Atm){
			code = "payment.atm";
		} else if(payment instanceof PostalOrder){
			code = "payment.postalOrder";
		} else{
			throw new RuntimeException("undefied payment type:" + payment);
		}
		
		return code;
	}
	
	/**
	 * Get message code by given invoice.
	 * @param invoice
	 * @return
	 */
	public static final String getInvoiceMessageCode(Invoice invoice){
		Validate.notNull(invoice, "invoice shall always not be null");
		String code = null;
		
		if(invoice instanceof DuplicateInvoice){
			code = "invoice.duplicateInvoice";
		} else if(invoice instanceof DuplicateInvoiceWithCashier){
			code = "invoice.duplicateInvoiceWithCashier";
		} else if(invoice instanceof Invoice){
			code = "invoice.invoice";
		} else{
			throw new RuntimeException("undefined invoice type:" + invoice);
		}
		
		return code;
	}
	
	/**
	 * @param status
	 * @return
	 */
	public static final String getOrderStatusMessageCode(OrderStatus status){
		Validate.notNull(status, "order status shall always not be null/empty");
		
		String code = null;
		
		switch(status){
		
		case NEW:
			code = "order.status.new";
			break;
		case WAIT_FOR_REPLENISHMENT:
			code = "order.status.waitForReplenishment";
			break;
		case UNDER_PROCESSING:
			code = "order.status.underProcessing";
			break;
		case UNDER_DELIVERY:
			code = "order.status.underDelivery";
			break;
		case RECEIVED:
			code = "order.status.received";
			break;
		case IN_CONVENIENT_STORE:
			code = "order.status.inConvenientStore";
			break;
		case CLOSE:
			code = "order.status.close";
			break;
		case CANCEL:
			code = "order.status.cancel";
			break;
		default:	
			throw new RuntimeException("undefined order status:" + status);
		}
		
		return code;
	}
	
	/**
	 * @param status
	 * @return
	 */
	public static final String getOrderItemStatusMessageCode(OrderItemStatus status){
		Validate.notNull(status, "order status shall always not be null/empty");
		
		String code = null;
		
		switch(status){
		
		case OK:
			code = "orderItem.status.ok";
			break;
		case WAIT:
			code = "orderItem.status.wait";
			break;
		case DELIVERED:
			code = "orderItem.status.delivered";
			break;
		default:	
			throw new RuntimeException("undefined order status:" + status);
		}
		
		return code;
	}
	
	/**
	 * @param status
	 * @return
	 */
	public static final String getPickingListStatusMessageCode(PickingListStatus status){
		Validate.notNull(status, "order status shall always not be null/empty");
		
		String code = null;
		
		switch(status){
		
		case UNDER_PROCESSING:
			code = "pickingList.status.underProcessing";
			break;
		case UNDER_DELIVERY:
			code = "pickingList.status.underDelivery";
			break;	
		case IN_CONVENIENT_STORE:
			code = "pickingList.status.inConvenientStore";
			break;
		case RECEIVED:
			code = "pickingList.status.received";
			break;
		case CLOSE:
			code = "pickingList.status.close";
			break;
		case CANCEL:
			code = "pickingList.status.cancel";
			break;
		default:	
			throw new RuntimeException("undefined pickingList status:" + status);
		}
		
		return code;
	}
	
	/**
	 * Check whether roleClassName in the roles.
	 * @param roles
	 * @param roleClassName
	 * @return
	 */
	public static boolean hasRole(String[] roles, String roleClassName){
		if(ArrayUtils.isNotEmpty(roles)){
			for(String role : roles){
				if(role.equals(roleClassName)){
					return true;
				}
			}
		}
		return false;
	}
	
	/**
	 * Get message code by given userAccount mode instance.
	 * @param userAccount
	 * @return
	 */
	public static String getUserAccountTypeMessageCode(UserAccount userAccount){
		Validate.notNull(userAccount, "userAccount shall always not be null");
		String msgCode = "";
		if(userAccount instanceof IndividualAccount){
			msgCode = "userAccount.type.individualAccount";
		} else if(userAccount instanceof OrganizationAccount){
			msgCode = "userAccount.type.organizationAccount";
		} else{
			throw new RuntimeException("undefined userAccount type:" + userAccount);
		}
		
		return msgCode;
	}
	
	/**
	 * Get all sub-categories id into a comma delimited double-quoted string.
	 * @param category
	 * @param delimiter
	 * @param quote
	 * @return
	 */
	public static String getAllSubCategoriesId(Category category, String delimiter, String quote){
		Validate.notNull(category, "category shall always not be null");
		StringBuffer idsString = new StringBuffer();
		Collection<Category> categories = null;
		String defaultDelimiter = ",";
		String defaultQuote = "\"";
		if(StringUtils.isNotEmpty(delimiter))
			defaultDelimiter = delimiter;
		if(StringUtils.isNotEmpty(quote))
			defaultQuote = quote;
		categories = category.getAllSubCategories();
		if(CollectionUtils.isNotEmpty(categories)){
			int a = 0;
			for(Category tmpCategory : categories){
				if(a == 0){
					idsString.append(defaultQuote + tmpCategory.getId() + defaultQuote);
				} else {
					idsString.append(defaultDelimiter + defaultQuote + tmpCategory.getId() + defaultQuote);
				}
				a++;
			}
		}
		
		return idsString.toString();
	}
	
	/**
	 * Get a comma delimited and double-quoted string from values of a given any type of collection.
	 * @param collection
	 * @param delimiter
	 * @param quote
	 * @return
	 */
	public static String getStringFromCollection(Collection<?> collection, String delimiter, String quote){
		Validate.notEmpty(collection, "collection shall always not be null/empty");
		String defaultDelimiter = ",";
		String defaultQuote = "\"";
		StringBuffer resultString = new StringBuffer(); 
		
		if(StringUtils.isNotEmpty(delimiter))
			defaultDelimiter = delimiter;
		if(StringUtils.isNotEmpty(quote))
			defaultQuote = quote;
		int a = 0;
		for(Object value : collection){
			if(a == 0){
				resultString.append(defaultQuote + value + defaultQuote);
			} else{
				resultString.append(defaultDelimiter + defaultQuote + value + defaultQuote);
			}
			a++;
		}
		return resultString.toString();
	}

}
